﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using TTEngine.Graphics;
using TTEngine.Resource;
using TTEngine.TTMath;
using voidbox;

namespace TTEngine.Graphics
{

    public class Render_Tiledmap : IRender
    {
        Mesh mesh;
        Material mat;
        IndexTex texIndex;
        TiledTex texTiled;
        public Vector2I startPos
        {
            get;
            private set;
        }
        public void SetTiledmap(Resource.ResourcePackage package, IndexTex indexTex, TiledTex tiledTex, Vector2I startpos, float scale)
        {
            startPos = startpos;
            this.mat = new Material(package, ResourceAll.GetNamedResource<ShaderProgram>("tiledmap"));
            this.mat.UpdateMatModel();
            this.mesh = new Mesh(package);
            this.mesh.UpdateVertexFormat(VertexFormatMgr.GetFormat_Vertex_UV_Color());
            this.Scale = scale;
            this.UpdateMesh((int)indexTex.Width, (int)indexTex.Height, startpos.X, startpos.Y, 0, tiledTex.TileSize * scale);
            this.texIndex = indexTex;
            this.texTiled = tiledTex;
            //uniform sampler2D texIndex; 
            //uniform sampler2D texTile; 
            //uniform float   tilesize;
            //uniform vec4     mapinfo;//xy map size, zw=tile texturesize
            this.mat._uniformTexs["texTile"].Value = tiledTex.Texture;
            this.mat._uniformTexs["texIndex"].Value = indexTex.Texture;
            this.mat._uniformFloats["tilesize"].Value = tiledTex.TileSize;
            this.mat._uniformVecs["mapinfo"].Value = new float[]{indexTex.Width, indexTex.Height
            , tiledTex.Width, tiledTex.Height };
        }
        public float Scale
        {
            get;
            private set;
        }

        private void UpdateMesh(int width, int height, int startX, int startY, float Z, float scale)
        {


            var stride = this.mesh.GetVertexFormat().VBOs[0].Stride;
            var vertexdata = new byte[stride * 6];
            unsafe
            {
                fixed (void* ptr = vertexdata)
                {
                    float* srcdata = (float*)ptr;
                    srcdata[stride / 4 * 0 + 0] = startX;//x
                    srcdata[stride / 4 * 0 + 1] = startY;//y
                    srcdata[stride / 4 * 0 + 2] = Z;//z
                    srcdata[stride / 4 * 0 + 3] = 0;//u
                    srcdata[stride / 4 * 0 + 4] = 0;//v

                    srcdata[stride / 4 * 1 + 0] = startX + width * scale;//x
                    srcdata[stride / 4 * 1 + 1] = startY;//y
                    srcdata[stride / 4 * 1 + 2] = Z;//z
                    srcdata[stride / 4 * 1 + 3] = 1;//u
                    srcdata[stride / 4 * 1 + 4] = 0;//v

                    srcdata[stride / 4 * 2 + 0] = startX;//x
                    srcdata[stride / 4 * 2 + 1] = startY + height * scale;//y
                    srcdata[stride / 4 * 2 + 2] = Z;//z
                    srcdata[stride / 4 * 2 + 3] = 0;//u
                    srcdata[stride / 4 * 2 + 4] = 1;//v

                    srcdata[stride / 4 * 3 + 0] = startX;//x
                    srcdata[stride / 4 * 3 + 1] = startY + height * scale;//y
                    srcdata[stride / 4 * 3 + 2] = Z;//z
                    srcdata[stride / 4 * 3 + 3] = 0;//u
                    srcdata[stride / 4 * 3 + 4] = 1;//v

                    srcdata[stride / 4 * 4 + 0] = startX + width * scale;//x
                    srcdata[stride / 4 * 4 + 1] = startY;//y
                    srcdata[stride / 4 * 4 + 2] = Z;//z
                    srcdata[stride / 4 * 4 + 3] = 1;//u
                    srcdata[stride / 4 * 4 + 4] = 0;//v

                    srcdata[stride / 4 * 5 + 0] = startX + width * scale;//x
                    srcdata[stride / 4 * 5 + 1] = startY + height * scale;//y
                    srcdata[stride / 4 * 5 + 2] = Z;//z
                    srcdata[stride / 4 * 5 + 3] = 1;//u
                    srcdata[stride / 4 * 5 + 4] = 1;//v
                }
            }




            this.mesh.UploadVertexBuffer(0, vertexdata, false, vertexdata.Length);


        }

        public void Update(ITarget target, Camera camera)
        {
            if (this.mat == null || this.mesh == null)
                return;
            this.mat.UpdateMatProj(target);
            this.mat.UpdateMatView(camera?.GetViewMatrix());
        }

        public void Render()
        {
            if (this.mat == null || this.mesh == null)
                return;
            this.mesh.Draw(this.mat);
        }


    }
}
